React Concurrent Mode感想スレ
身内向けのSNS(?)クライアントをReact Concurrent Renderingをフル活用して書き直すということをやってみている
APIの規模が小さいので割とすぐにフル機能のものが作れて楽なのだ
規模は小さいが、
OAuth2ベースの認証機構
データの正規化(タイムライン表示)
Infinite Loadingを含むページング処理
ストリームの管理
みたいなデータ取得周りの難しさは網羅している
反面、複雑なフォームみたいなのはない
思うこと
データ取得を上位階層に持ち上げるのが難しい
Render-as-You-Fetchパターンで必要
というかデータを利用するコンポーネントとデータ取得が離れているのが気に食わない
それコンポーネントじゃないだろという気持ちになったり
Prop Drillingの再来じゃん…って気持ちになったり
まあContextで解決できるのだが
これをするためにルータを書く必要がある
大変
解決した
Relayがヒントになった
コンポーネントの直上にgetInitialPropsを定義(これがFragmentに相当する)
Propsの定義にReturnType<typeof getInitialProps>を使うと非常に便利
そのコンポーネントを使うコンポーネントにも同様にgetInitialPropsを書き、下のコンポーネントのgetInitialPropsを合成して書く
これをSuspense直下までくり返し、Suspenseの上でgetInitialPropsを呼べば、全てのコンポーネントに必要なリソースを集めることに成功する
ページコンポーネントのgetInitialPropsをルータに渡したりするといい感
こんなのでうまくいくのか?という気がするが、Propsの型定義によって 間違ったことをすればすぐにエラーになってくれる
Suspense for Data Fetchingにおける「データフェッチングライブラリ」とは何者なのか
コンポーネントとデータのコロケーションをサポートする?
今回はgetInitialPropsをうまく書くためにAPIクライアントとキャッシュを結びつける層を用意した
これが相当するのかも
Reduxを封じられている
React Concurrent Renderingフレンドリーじゃない
でもこれなしでどうやって無駄な再レンダーを抑制しつつデータの正規化を行うんだろうという気持ち
正規化しないと欲しいレンダリング結果を得られないシーンがいくつか存在する
正規化が必要なオブジェクトは数百くらいにもなり得るのでContextで解決できるのか?という気持ちになる
まあContext & React.memoでいけそうな気もする
困ったら use-context-selector つかいましょう
という夢を見ていた
確かにReduxストアはプレーンなJSオブジェクトしか受け付けないのでここに非同期管理オブジェクトを入れることはできない
しかし、ReduxのSelectorはデータへの参照として機能する
ということはLodable<Selector>みたいなものを非同期処理で作って返せばReduxストアは処理完了後のプレーンなJSオブジェクトだけ見ていることができる
code:tsx
export const getInitialProps = (store: Store) => {
/* 何らかの非同期処理 */
const selectorLoadable: Loadable<Selector>
return {
selectorLoadable
}
}
export const Component = ({ selectorLoadable }) => {
const data = useSelector(selectorLoadable.read())
/* 描画処理 */
}
もちろん今のuseSelectorはConcurrent Mode非対応なのでuseSyncExternalStoreなどを使ってよしなにやる
GraphQLって便利なんだなあ
Fragmentが強い
初回ロードでは必要なクエリを構成する要素として
マウント後はリソースの更新を追従するためのキャッシュからのセレクタとして動作する
useTransitionのおかげでReact.lazyの描画もいい感じになっていて完全体という気持ちになる